/** \file TeamManager.hpp Contains the Definition of the TeamManager Class.
 *  \author Adrian Schweizer
 *  \created  $Sa 18 Aug 03:48:01 pm CEST 2007 schwadri@SchwadriComp.local$
 *  \modified $Sa 06 Okt 06:26:12 pm CEST 2007 schwadri@SchwadriLaptop$
 */

#ifndef _game_TeamManager_hpp_
#define _game_TeamManager_hpp_

#include "Common.hpp"
#include "../network/Types.hpp"
#include "Team.hpp"

namespace game {

    /** \brief
     */
    class TeamManager : private boost::noncopyable
    {
        typedef std::vector<Team>                   team_container;
    public:
        static const int LIMIT_NUMBER_OF_TEAMS   =   4;

        typedef team_container::iterator            team_iterator;
        typedef team_container::iterator            iterator;
        typedef team_container::const_iterator      const_iterator;
        typedef team_container::const_iterator      const_team_iterator;

        TeamManager();
        ~TeamManager();

        /** \name Player Container Functionality*///@{
        const Player&           operator[](Player::Id pid) const { return m_teams[pid.team].m_players[pid.player]; }
        Player&                 operator[](Player::Id pid)       { return m_teams[pid.team].m_players[pid.player]; }
        //@}

        /** \name Team Container Functionality*///@{
        const Team&             operator[](char teamid) const { return m_teams[teamid]; }
        Team&                   operator[](char teamid)       { return m_teams[teamid]; }
        //@}

        /** \name Iterator methods*/ //@{
        const_team_iterator     begin() const   { return m_teams.begin(); }
        const_team_iterator     end()   const   { return m_teams.end(); }
        team_iterator           begin()         { return m_teams.begin(); }
        team_iterator           end()           { return m_teams.end(); }
        //@}
        int                     NumberOfTeams() const    { return static_cast<int>(m_teams.size()); }

        network::Client::Id     ClientFromPlayer(Player::Id pid)          { return m_teams[pid.team].m_players[pid.player].ClientId(); }
        Player::Id              PlayerFromClient(network::Client::Id cid) { return m_cid_to_pid[cid]; }


        void                    RemoveTeam(char tid);
        void                    CreateNewTeam();

        void                    RemovePlayer(Player::Id pid);

        Team&                   Spectators()                    { return m_spectators; }
        const Team&             Spectators() const              { return m_spectators; }

        /** \brief accepts a generic visitor and lets them visit all the Teams (except the Spectator Team)*/
        template<class Visitor>
            void  Accept(Visitor & v)
            {
                foreach(Team & t, m_teams)
                    v.Visit(t);
            }
    private:
        void ShiftTeamAndPlayerIds(team_iterator titer);
        friend class Team;
        team_container                  m_teams;        ///< contains all teams participating in the game
        Team                            m_spectators;   ///< contains all the spectators (teamid=-1)
        std::vector<Player::Id>         m_cid_to_pid;   ///< mapping from client id to player id
    };

    struct  SetPlayerReadyVisitor
    {
        SetPlayerReadyVisitor(bool ready)
        :   m_ready(ready)
        { }

        void Visit(TeamManager & t)
        {
            t.Accept(*this);
        }

        void Visit(Team & t)
        {
            t.Accept(*this);
        }

        void Visit(Player & p)
        {
            p.Ready(m_ready);
        }
    private:
        bool m_ready;
    };



} // namespace game

#endif // _game_TeamManager_hpp_
